home *** CD-ROM | disk | FTP | other *** search
- ; Profiler for Sherlock--low level routines
- ;
- ; WARNING! use this file at your own risk. See further warnings below.
- ;
- ; source: prf.asm
- ; started: November 10, 1986
- ; version: July 22, 1988
- ;
- ;
- ; Copyright (C) 1987, 1988 by Edward K. Ream.
- ; All Rights reserved.
- ;
- ;
- ; This file contains an interrupt handler for timing interrupts,
- ; and routines to install and de-install the handler.
- ;
- ; NOTE: This file is required only if the TIME_STATS variable is
- ; #define'd in the file SHERLOCK.C.
- ;
- ; NOTE: Assemble this file with the Microsoft MASM assembler and
- ; link this file with the Microsoft or TURBO C linkers.
- ; Use the /MX and /ML options when assembling this file.
- ;
- ; NOTE: Use the /DNEAR option on the MASM command line when producing
- ; a .obj file to be used with memory models with small code
- ; space, namely the Microsoft small and compact models. Do NOT
- ; use the /DNEAR option when using the other memory models.
- ;
- ; WARNING! You must MAKE SURE that you change this code correctly
- ; reflects the memory model you are using in your C code.
- ; If you get this wrong, the code will die a quick death.
- ;
- ; WARNING! USE THIS CODE AT YOUR OWN RISK. This code may cause
- ; your system to hang. This code contains potential machine
- ; dependencies. See further warnings below. However, this
- ; code has been tested on both PC clones and AT clones.
- ;
- ; WARNING! The code changes interrupts 33-36 in an attempt to trap
- ; ALL exit points from the program. If this attempt is not
- ; successful, the system will hang and a reboot is the only
- ; way out. DO NOT, repeat DO NOT, use this code if that
- ; possibility is unacceptable!!!
- ;
- ; WARNING! The code messes with the timing rate of the system clock to
- ; increase the number of timing interrupts without changing
- ; number of 'tick' interrupts visible to the rest of the
- ; system. To do this, it must touch the underlying clock
- ; hardware. In particular this code fiddles with the 8251
- ; timer chip. THIS CODE MAY NOT WORK if that chip does not
- ; exist on your machine.
- ;
-
- TITLE prf.asm
-
- DGROUP GROUP _DATA
- ASSUME ds:DGROUP
-
- ;
- ; Declare variables which are defined in sherlock.c
- ; (sl_count and sl_speed).
- ; Also define local variables.
- ;
-
- _DATA SEGMENT WORD PUBLIC 'DATA'
-
- EXTRN _sl_count:DWORD
- EXTRN _sl_speed:WORD
-
- timer_count dw 1 ;internal timer count
- timer_speed dw 1 ;internal timer speed
- installed db 0 ;true = routines installed
-
- _DATA ENDS
-
- _TEXT SEGMENT BYTE PUBLIC 'CODE'
- ASSUME cs:_TEXT
-
- ;
- ; Storage area for saved interrupt vectors.
- ;
- ; The interrupt installation routine, sl_von, saves the old value of
- ; the interrupt vectors here. The de-initialization routine, sl_voff,
- ; restores the vectors using these values.
- ;
- ; WARNING! We must attempt to trap ALL exits from the program, because
- ; we can not rely on the program itself to call sl_voff.
- ; After all, we ARE debugging, so aborting the program must be
- ; expected. THIS CREATES A PROBLEM, because if the program
- ; ever terminates without sl_von being called, the interrupt
- ; handlers will not be restored and the system will hang.
- ;
- ; These vectors MUST be in the code segment; Indeed, when we do the
- ; jump-indirect that gets us to the machine's routines, we must have
- ; all the processor registers and flags restored to their original
- ; values. If we change ds, (in order to pick these out of the data
- ; segment and do the indirect jump), there's no way to change ds back
- ; again to whatever the caller had it.
- ;
- ; The fact that these vectors are in the code segment instead of the
- ; data segment makes the code below much more tricky than usual.
- ; Be warned. Do not change the code in sl_von and sl_voff without
- ; careful thought.
- ;
-
- old_8 label DWORD ;Tick interrupt vector
- ofs8 dw 0 ;offset
- seg8 dw 0 ;segment
-
- old_33 label DWORD ;Invoke "DOS 21 hex" interrupt vector
- ofs33 dw 0 ;offset
- seg33 dw 0 ;segment
-
- old_34 label DWORD ;Terminate Address
- ofs34 dw 0 ;offset
- seg34 dw 0 ;segment
-
- old_35 label DWORD ;Break Address
- ofs35 dw 0 ;offset
- seg35 dw 0 ;segment
-
- old_36 label DWORD ;Critical Error Handler address
- ofs36 dw 0 ;offset
- seg36 dw 0 ;segment
-
- ;
- ; Install the interrupt handler for the timer (tick) interrupt.
- ;
- ; It contains a safeguard against overwriting the old_xx vectors
- ; so as to minimize the chances of getting the new values of
- ; the vectors saved, and thereby having this code locked into
- ; place forever.
- ;
-
- PUBLIC _sl_von
-
- IFDEF NEAR
- _sl_von proc near ;for small memory models
- ELSE
- _sl_von proc far ;for large memory models
- ENDIF
-
- push es
- push ds
- mov ax,DGROUP ;actually, needed only for multisegment
- mov ds,ax ;programs
- cli ;disable maskable intertupts
- ;
- ; WARNING! The set_timer routine contains machine dependent code.
- ; It MAY NOT WORK on your machine.
- ;
-
- call set_timer
-
- ;
- ; Do not replace vectors if they are already replaced.
- ;
- test installed,0ffh ;vectors already installed?
- jz noskip
- jmp skipvec
- noskip:
- mov installed,0ffh
- ;
- ; Replace existing 'tick' interrupt (interrupt 8).
- ;
- mov ax,cs
- mov ds,ax
- ;
- ; Caution: these settings use ds=cs, not ds of this module's data!!!
- ;
- mov ah,35h ;get interrupt vector
- mov al,8 ;8
- int 21h ;into ES:BX
-
- mov seg8,es
- mov ofs8,bx
- mov dx,offset svc_timer
-
- mov ah,25h ;set interrupt vector
- mov al,8 ;8
- int 21h ;from DS:DX
-
- ;
- ; Replace existing interrupt 33 (21 hex).
- ;
- mov ah,35h ;get interrupt vector
- mov al,33 ;33
- int 21h ;into ES:BX
-
- mov seg33,es
- mov ofs33,bx
- mov dx,offset do33
-
- mov ah,25h ;set interrupt vector
- mov al,33 ;33
- int 21h
- ;
- ; Replace existing interrupt 34 (decimal).
- ;
- mov ah,35h ;get interrupt vector
- mov al,34 ;34
- int 21h ;into ES:BX
-
- mov seg34,es
- mov ofs34,bx
- mov dx,offset rest34
-
- mov ah,25h ;set interrupt vector
- mov al,34 ;34
- int 21h
- ;
- ; Replace existing interrupt 35.
- ;
- mov ah,35h ;get interrupt vector
- mov al,35 ;35
- int 21h ;into ES:BX
-
- mov seg35,es ;:cs
- mov ofs35,bx
- mov dx,offset rest35
-
- mov ah,25h ;set interrupt vector
- mov al,35 ;35
- int 21h
- ;
- ; Replace existing interrupt 36.
- ;
- mov ah,35h ;get interrupt vector
- mov al,36 ;36
- int 21h ;into ES:BX
-
- mov seg36,es ;:cs
- mov ofs36,bx
- mov dx,offset rest36
-
- mov ah,25h ;set interrupt vector
- mov al,36 ;36
- int 21h
- ;
- ; Caution: ds is still cs here!
- ;
- skipvec:
- sti ;enable maskable interrupts
- pop ds
- pop es
- ret
-
- _sl_von ENDP
-
- ;
- ; This routine is entered when the program terminates, and is normally
- ; entered by way of one of the altered interrupts 33-36.
- ;
- ; It is permissible to call it more than once, since the saved vectors
- ; are not overwritten by anything.
- ;
-
- PUBLIC _sl_voff
-
- IFDEF NEAR
- _sl_voff PROC near ;for small memory models
- ELSE
- _sl_voff PROC far ;for large memory models
- ENDIF
-
- push ds
- push dx
- push ax
- mov ax,DGROUP
- mov ds,ax
- cli ;disable maskable interrupts
- ;
- ; Restore timer 0 to power-up value.
- ; WARNING! This code MAY NOT WORK on your machine.
- ;
- mov al,36h
- out 43h,al
- mov al,0
- out 40h,al
- out 40h,al
- ;
- ; Cancel installation flag.
- ;
- mov installed,0
- ;
- ; Caution: ds is obviously no good from here on down!
- ;
- ; Restore 'tick' interrupt (interrupt 8).
- ;
- lds dx,old_8
- mov ah,25h ;set interrupt vector
- mov al,8 ;
- int 21h
- ;
- ; Restore interrupt 33.
- ;
- lds dx,old_33
- mov ah,25h ;set interrupt vector
- mov al,33 ;33
- int 21h
- ;
- ; Restore interrupt 34.
- ;
- lds dx,old_34 ;cs:old_34, of course
- mov ah,25h ;set interrupt vector
- mov al,34 ;34
- int 21h
- ;
- ; Restore interrupt 35.
- ;
- lds dx,old_35
- mov ah,25h ;set interrupt vector
- mov al,35 ;35
- int 21h
- ;
- ; Restore interrupt 36.
- ;
- lds dx,old_36
- mov ah,25h ;set interrupt vector
- mov al,36 ;36
- int 21h
- ;
- ; Caution: ds is not valid here.
- ;
- pop ax
- pop dx
- pop ds
- sti
- ret
- ;
- ; The following routines replace the original interrupt vectors 33-36.
- ; They simply de-install the timer interrupt (svc_timer) and then chain
- ; to the original interrupt vector.
- ;
- ; The do33 (dos 21 hex) interrupt is slightly more complicated.
- ; This is the DOS Functions software interrupt. All DOS functions except
- ; function 0 (terminate) and 4c hex (terminate process) are passed
- ; through unchanged. Functions 0 and 4c cause the timer interrupt to
- ; be de-installed.
- ;
- do33:
- cmp ah,4ch ;terminate process?
- je rest33
- cmp ah,0 ;terminate?
- je rest33
- jmp old_33 ;just pass through the request unchanged.
-
- rest33:
- call _sl_voff
- jmp old_33
- rest34:
- call _sl_voff
- jmp old_34
- rest35:
- call _sl_voff
- jmp old_35
- rest36:
- call _sl_voff
- jmp old_36
-
- _sl_voff ENDP
-
- ;
- ; Service a timer interrupt.
- ;
- ; This code bumps the (long) sl_count counter defined in sherlock.c.
- ; Then, depending on the 'speed up factor', it either chains to the
- ; original 'tick' interrupt routine or returns from the interrupt
- ; immediately.
- ;
- svc_timer PROC near
-
- push ds
- push ax
- ;
- ; The next statement has to use DGROUP, not _DATA, as the segment base.
- ; Ours is not to reason why...
- ;
- ; NOTE: even in a small-model program, the ds is apt not to be set
- ; correctly at the entry to svc_timer, since the int could occur
- ; from inside a utility or DOS function not part of the C program.
- ; In Microsoft C, the ds setting at the outset (__astart) isn't the
- ; same as the setting at _main, even for the small model!
- ;
- mov ax,DGROUP
- mov ds,ax
-
- inc WORD PTR _sl_count
- jnz svc_1
- inc WORD PTR _sl_count+2
- svc_1:
- ;
- ; See if we should chain to the original tick interrupt or
- ; return from the interrupt right away. This depends on the speed-up
- ; factor, i.e., the settings of sl_speed and timer_count.
- ;
- dec timer_count
- jnz skip
- mov ax,timer_speed
- mov timer_count,ax
- cmp ax,_sl_speed
- jz svc_2
- call set_timer
- ;
- ; Chain to the original interrupt.
- ;
- svc_2:
- pop ax
- pop ds
- jmp old_8
- ;
- ; Return from the interrupt without chaining to the original interrupt.
- ;
- skip:
- mov al,20h
- out 20h,al ;send EOI to 8259
- pop ax
- pop ds
- iret ;return from interrupt
-
- svc_timer ENDP
-
- ;
- ; Set up timer according to speed ratio.
- ; This needs to push all registers it uses, except ax.
- ;
- ; WARNING! This is MACHINE DEPENDENT CODE. There is NO guarantee
- ; that this code will work on your machine.
- ; If it does not work, you may just comment it all out, but
- ; then you will be stuck with the 18 hz. default clock rate.
- ;
- set_timer PROC NEAR
- push dx
- mov ax,_sl_speed
- cmp ax,0
- jnz set_1
- mov ax,1
- set_1:
- mov timer_speed,ax
- mov timer_count,ax
-
- mov ax,0ffffh
- mov dx,0
- div timer_speed ;sl_speed is a word, so it's 32:16
- mov dx,ax ;dx = setting to be put into timer
-
- mov al,36h ;timer 0, mode 3
- out 43h,al
- mov al,dl ;lsb
- out 40h,al
- mov al,dh ;msb
- out 40h,al
- pop dx
- ret
- set_timer ENDP
-
- _TEXT ENDS
-
- END
-